import java.io.*;
import java.nio.charset.*;
import java.util.*;

/* 
 * Convert file(s) from one encoding to another recursively 
 * and write back to the original file(s), Since this is not
 * an atomic operation, that is, one cannot roll back the files
 * to the original states after the operation is performed, it 
 * is highly recommended that target files should be backuped 
 * before using this tool!
 */
public class jconv {
   private static final List<File> failedFiles=new ArrayList<File>();
   private static void convertFile(File file, String fromEncoding, String toEncoding) throws IOException {

      if(file.isDirectory()) {
         File[] ls=file.listFiles();
         for(File f: ls) {
            convertFile(f, fromEncoding, toEncoding);
         }
      } else {
         System.out.print("converting '"+file+"'...");
         //[ read
         StringBuilder sb=new StringBuilder();
         InputStreamReader reader=null;
         try {
            reader=new InputStreamReader(
                  new FileInputStream(file), fromEncoding);
            int c;
            while((c=reader.read())!=-1) {
               sb.append((char)c);
            }
         } catch(IOException e) {
            System.err.println("failed!");
            failedFiles.add(file);
            return;
         } finally {
            if(reader!=null) reader.close();
         }
         if(sb.length()==0) return; 
         final String res=sb.toString();

         //[ write
         OutputStreamWriter writer=null;
         try {
            FileOutputStream fout=new FileOutputStream(file);
            writer=new OutputStreamWriter(fout, toEncoding);
            writer.write(res);
         } catch(IOException e) {
            System.err.println("failed!");
            failedFiles.add(file);
            return;
         } finally {
            if(writer!=null) writer.close();
         }
         System.out.println("ok!");
      }
   }
   public static void start(String[] args) {
      if(args.length<3) {
         System.out.println("Usage: java jconv [input-file]* [from-encoding] [to-encoding]");
         return;
      }
      final String toEncoding=args[args.length-1];
      final String fromEncoding=args[args.length-2];
      if(!Charset.isSupported(fromEncoding)) {
         System.out.println("charset '"+fromEncoding+"' is not supported!");
         return;
      }
      if(!Charset.isSupported(toEncoding)) {
         System.out.println("charset '"+toEncoding+"' is not supported!");
         return;
      }
      System.out.print("override existing file(s)?(y/n)");
      final Scanner cin=new Scanner(System.in);
      final String input=cin.next();
      if(!input.trim().equalsIgnoreCase("y")) {
         return;
      }
      try {
         for(int i=0; i<args.length-2; i++) {
            File f=new File(args[0]);
            convertFile(f, fromEncoding, toEncoding);
         }
         System.out.println("complete!");
         if(failedFiles.isEmpty()) {
            System.out.println("All files are converted!");
         } else {
            System.err.println("The following files are not converted due to reading/writing error:");
            for(File f: failedFiles) {
               System.err.println(f.getName());
            }
         }
      } catch(IOException e) {
         e.printStackTrace();
      }
   
   }

   public static void main(String[] args) {
      start(args);
   }
}
